package cn.org.xiaoweiba.graduationdesign.bookmall.aspect;

import cn.org.xiaoweiba.graduationdesign.bookmall.annotation.mail.MailLegalAnnotation;
import cn.org.xiaoweiba.graduationdesign.bookmall.annotation.mail.MailLegalObjectAnnotation;
import cn.org.xiaoweiba.graduationdesign.bookmall.annotation.mail.MailLegalParameterAnnotation;
import cn.org.xiaoweiba.graduationdesign.bookmall.constant.ResponseResultMessageConstant;
import cn.org.xiaoweiba.graduationdesign.bookmall.dto.result.ClientErrorResponseResult;
import cn.org.xiaoweiba.graduationdesign.bookmall.dto.result.ServerErrorResponseResult;
import cn.org.xiaoweiba.graduationdesign.bookmall.utils.AspectUtil;
import cn.org.xiaoweiba.graduationdesign.bookmall.utils.MailUtil;
import cn.org.xiaoweiba.graduationdesign.bookmall.utils.ReflectUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Arrays;

/**
 * 判断邮箱是否合法的切面类
 */
@Aspect
@Order(3)
@Component
public class MailLegalAspect {

    @Pointcut("@annotation(cn.org.xiaoweiba.graduationdesign.bookmall.annotation.mail.MailLegalAnnotation)")
    private void pointCut() {
    }

    /**
     * 判断邮箱是否合法
     *
     * @param proceedingJoinPoint 切点
     * @return 响应结果对象
     */
    @Around("pointCut()")
    public Object judgeMailIsLegalAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
        // 对需要进行判断邮箱是否的合法的参数进行判断处理
        Object[] results = AspectUtil.doParamHandleBeforeAdvice(
                proceedingJoinPoint,
                MailLegalObjectAnnotation.class,
                (Object arg) -> {
                    // 判断对象形式参数中被 MailLegalAnnotation 标注的字段邮箱是否合法
                    return judgeMailIsLegalObjField(arg);
                },
                MailLegalParameterAnnotation.class,
                (Object arg) -> {
                    // 判断当前参数 邮箱是否合法
                    return MailUtil.mailIsLegal((String) arg);
                }
        );
        // 存在不合法的邮箱，返回错误响应结果对象
        if (Arrays.stream(results).anyMatch(result -> (Boolean) result == false)) {
            return ClientErrorResponseResult.errorResult(ResponseResultMessageConstant.MAIL_IS_ILLEGAL);
        }
        try {
            // 执行切点方法并返回切点方法的执行结果
            return proceedingJoinPoint.proceed();
        } catch (Throwable e) {
            // 响应服务器异常
            return ServerErrorResponseResult.errorResult(ResponseResultMessageConstant.SERVER_ERROR);
        }
    }

    /**
     * 判断对象中被 MailLegalAnnotation 标注的字段的邮箱
     * 是否合法
     *
     * @param object 对象
     * @return 合法 true；不合法 false
     */
    private Boolean judgeMailIsLegalObjField(Object object) {
        try {
            ReflectUtil.doObjectAllFieldHandleByAnnotation(
                    object,
                    (Object obj, Field field, Annotation[] annotations) -> {
                        // 当前字段没有被 MailLegalAnnotation 标注直接判断下一个字段
                        if (!ReflectUtil.judgeContainAnnotation(annotations, MailLegalAnnotation.class)) {
                            return;
                        }
                        // 当前字段被 MailLegalAnnotation 标注，需要进行判断
                        // 获取当前字段的值
                        String fieldValue = null;
                        try {
                            fieldValue = (String) ReflectUtil.getFieldValue(obj, field);
                        } catch (IllegalAccessException ignored) {

                        }
                        // 如果邮箱不合法，抛出错误
                        if (!MailUtil.mailIsLegal(fieldValue)) {
                            throw new RuntimeException();
                        }
                    }
            );
        } catch (Exception e) {
            // 捕获到因邮箱不合法抛出的错误
            return false;
        }
        // 邮箱合法
        return true;
    }

}
